package com.gin.no_gay_alliance.manager;

import android.util.Log;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.gin.jackson.utils.JacksonUtils;
import com.gin.jackson.utils.ObjectUtils;
import com.gin.nga.callback.DocCallback;
import com.gin.nga.callback.JsonCallback;
import com.gin.nga.client.NgaClient;
import com.gin.nga.exception.NgaException;
import com.gin.nga.exception.NgaServerException;
import com.gin.nga.method.ReadApi;
import com.gin.nga.params.read.ReadReplyParam;
import com.gin.nga.params.read.ReadTopicParam;
import com.gin.nga.response.body.ReadBody;
import com.gin.nga.response.field.SimpleUserInfo;
import com.gin.nga.response.field.user.UserInfoRead;
import com.gin.no_gay_alliance.adpter.reply.ReplyItemAdapter;
import com.gin.no_gay_alliance.app.MyApplication;
import com.gin.no_gay_alliance.callback.Bundle;
import com.gin.no_gay_alliance.callback.Callback;
import com.gin.no_gay_alliance.database.dao.NgaUserInfoDao;
import com.gin.no_gay_alliance.database.entity.NgaUserInfo;
import com.gin.no_gay_alliance.database.entity.ReplyHistory;
import com.gin.no_gay_alliance.database.entity.ReplyHistoryTopic;
import com.gin.no_gay_alliance.database.manager.ReplyHistoryManager;
import com.gin.no_gay_alliance.manager.provider.ResourceManager;
import com.gin.no_gay_alliance.viewmodel.ReadItem;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 阅读主题/回复 管理器
 *
 * @author : ginstone
 * @version : v1.0.0
 * @since : 2023/8/14 14:45
 **/
public class TopicReadManager {
    public static final String TAG = TopicReadManager.class.getSimpleName();
    private final HashMap<String, Bundle<ReadItem>> cache = new HashMap<>();

    public TopicReadManager() {
        Log.d(this.getClass().getSimpleName(), "创建 阅读主题/回复 管理器");
    }

    /**
     * 清空所有缓存
     */
    public void clear() {
        cache.clear();
    }

    /**
     * 读取主题的某一页
     *
     * @param ignoreCache 是否忽略缓存
     * @param param       参数
     * @param callback    回调
     */
    public void readTopic(boolean ignoreCache, ReadTopicParam param, Callback<ReadItem> callback) {
        // 检查缓存
        String key = getKey(param);
        if (Bundle.checkCache(ignoreCache, cache, key, callback)) {
            return;
        }
        callback.beforeRequest();

        NgaClient client = MyApplication.getClient();
        ReadApi.readTopic(client, param).async(new JsonCallback<ReadBody>() {
            @Override
            public void onSuccess(ReadBody body) {
                Log.d(TAG, "readTopic: " + key);
                TopicReadManager.this.onSuccess(body, key, callback);
            }

            @Override
            public void handleException(NgaException e) {
                if (e instanceof NgaServerException && e.getCode() == 500) {
                    Log.w(TAG, "handleException: " + "解析错误，使用doc请求");
                    ReadApi.readTopicDoc(client, param).async(new DocCallback<ReadBody>() {
                        @Override
                        public void onSuccess(ReadBody body) {
                            Log.d(TAG, "readTopicDoc: " + key);
                            TopicReadManager.this.onSuccess(body, key, callback);
                        }
                    });
                }
                super.handleException(e);
                callback.handleException(e);
            }
        });
    }

    /**
     * 读取单个回复
     *
     * @param ignoreCache 是否忽略缓存
     * @param param       参数
     * @param callback    回调
     */
    public void readReply(boolean ignoreCache, ReadReplyParam param, Callback<ReadItem> callback) {
        // 检查缓存
        String key = getKey(param);
        if (Bundle.checkCache(ignoreCache, cache, key, callback)) {
            return;
        }
        callback.beforeRequest();

        NgaClient client = MyApplication.getClient();
        ReadApi.readReply(client, param).async(new JsonCallback<ReadBody>() {
            @Override
            public void onSuccess(ReadBody body) {
                Log.d(TAG, "readReply: " + key);
                TopicReadManager.this.onSuccess(body, key, callback);
            }

            @Override
            public void handleException(NgaException e) {
                if (e instanceof NgaServerException && e.getCode() == 500) {
                    Log.w(TAG, "handleException: " + "解析错误，使用doc请求");
                    ReadApi.readReplyDoc(client, param).async(new DocCallback<ReadBody>() {
                        @Override
                        public void onSuccess(ReadBody body) {
                            Log.d(TAG, "readReplyDoc: " + key);
                            TopicReadManager.this.onSuccess(body, key, callback);
                        }
                    });
                }
                super.handleException(e);
            }
        });
    }

    /**
     * 请求成功的回调
     *
     * @param body     响应结果
     * @param key      key
     * @param callback 回调
     */
    private void onSuccess(ReadBody body, String key, Callback<ReadItem> callback) {
        saveCache(body.getUserContext().getUserInfo());

        // 请求buff头像数据
        ResourceManager.commonUiProvider().async(false, data -> {
            // 注入ui数据
            body.getUserContext().setCommonUiData(data);
            // 请求IP
            UserInfoManager userInfoManager = MyApplication.app.managerFactory.getUserInfoManager();
            body.getUserContext().getUserInfo().values().stream()
                    .filter(user -> !ReplyItemAdapter.SHOW_STATUS.contains(user.getAccountStatus()))
                    .map(SimpleUserInfo::getUserId)
                    .forEach(userId -> userInfoManager.getIpLocation(userId, s -> {
                    }));

            ReadItem readItem = new ReadItem(body);
            // 记录回复历史, 单回复模式和只看模式不记录
            if (!key.contains("replyId") && !key.contains("authorid")) {
                Log.d(TAG, "onSuccess: " + key);
                recordReplyHistory(readItem);
            }
            // 保存缓存
            cache.put(key, new Bundle<>(readItem));
            callback.onSuccess(readItem);
        });
    }

    /**
     * 缓存用户账号状态和货币数据
     *
     * @param userMap 用户信息
     */
    public static void saveCache(Map<Long, UserInfoRead> userMap) {
        NgaUserInfoDao ngaUserInfoDao = MyApplication.app.ngaDatabase.ngaUserInfoDao();
        long now = System.currentTimeMillis() / 1000;
        Collection<UserInfoRead> userInfo = userMap.values();

        // 检查是否有已存在的用户
        long[] userId = userInfo.stream().mapToLong(SimpleUserInfo::getUserId).toArray();
        List<NgaUserInfo> existUser = ngaUserInfoDao.listById(userId);
        if (!ObjectUtils.isEmpty(existUser)) {
            for (NgaUserInfo user : existUser) {
                UserInfoRead res = userMap.get(user.userId);
                if (res != null) {
                    user.accountStatus = res.getAccountStatus();
                    user.accountStatusTimestamp = now;
                    user.money = res.getMoney();
                    user.moneyTimestamp = now;
//                    Log.d(TAG, "更新账号状态: " + user.username + " " + user.accountStatus);
                }
            }
            ngaUserInfoDao.update(existUser);
        }
        Set<Long> existUserId = existUser.stream().map(u -> u.userId).collect(Collectors.toSet());

        // 新用户
        List<NgaUserInfo> newUser = userInfo.stream()
                .filter(u -> !existUserId.contains(u.getUserId()))
                .map(NgaUserInfo::new)
                .collect(Collectors.toList());
        if (!ObjectUtils.isEmpty(newUser)) {
            for (NgaUserInfo user : newUser) {
                Log.d(TAG, "增加新账号: " + user.username + " " + user.accountStatus);
            }
            ngaUserInfoDao.add(newUser);
        }
    }

    /**
     * 记录回复历史
     *
     * @param data
     */
    private static void recordReplyHistory(ReadItem data) {
        ReplyHistoryTopic topic = new ReplyHistoryTopic(data.topicId, data.title);
        List<ReplyHistory> replyHistories = data.replyItems.stream()
                .filter(i -> i.replyId != null)
                .filter(i -> i.topicId != null)
                .map(ReplyHistory::new)
                .collect(Collectors.toList());
        ReplyHistoryManager.record(topic, replyHistories);
    }

    /**
     * 根据param生成key
     *
     * @param param 参数
     * @return key
     */
    private static String getKey(Object param) {
        try {
            String typeName = param.getClass().getSimpleName();
            String value = JacksonUtils.MAPPER.writeValueAsString(param);
            return (typeName + value).replace("\n", "").replace(" ", "");
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

}
